﻿using System;
using System.Collections.Generic;
using System.Text;

namespace DimensionsHelper.Common.Utils;

public static class Extension
{
    /// <summary>
    ///     向字典中设置指定键的值，如果键不存在，将创建新的键值对。
    /// </summary>
    /// <typeparam name="TK"></typeparam>
    /// <typeparam name="TV"></typeparam>
    /// <param name="dictionary"></param>
    /// <param name="key">键值，不可为null</param>
    /// <param name="value">设置的新值</param>
    public static void SetValue<TK, TV>(this IDictionary<TK, TV> dictionary, TK key, TV value)
    {
        dictionary[key] = value;
    }

    public static bool TryAdd<TK, TV>(this Dictionary<TK, TV> dictionary, TK key, TV value) where TK : notnull
    {
        return dictionary.TryAdd(key, value);
    }

    public static bool Remove<TK, TV>(this Dictionary<TK, TV?> dictionary, TK key, out TV? value) where TK : notnull
    {
        return dictionary.TryGetValue(key, out value) && dictionary.Remove(key);
    }

    public static bool TryPeek<T>(this Stack<T> stack, out T value)
    {
        value = default!;

        if (stack.Count == 0)
        {
            return false;
        }

        value = stack.Peek();
        return true;
    }

    public static bool TryPop<T>(this Stack<T> stack, out T value)
    {
        value = default!;

        if (stack.Count == 0)
        {
            return false;
        }

        value = stack.Pop();
        return true;
    }


    /// <summary>
    ///     向字典中添加新的值类型对象或者更新已有值类型对象
    /// </summary>
    /// <typeparam name="TK"></typeparam>
    /// <typeparam name="TV"></typeparam>
    /// <param name="dictionary"></param>
    /// <param name="key">关键字</param>
    /// <param name="factory">值类型对象创建函数</param>
    /// <param name="updater">更新值类型对象的回调函数</param>
    public static void AddOrUpdate<TK, TV>(this IDictionary<TK, TV> dictionary, TK key, Func<TV> factory,
        Action<TV> updater)
    {
        if (!dictionary.TryGetValue(key, out var value))
        {
            value = factory();
            dictionary.Add(key, value);
        }

        updater(value);
    }


    public static TV GetValue<TK, TV>(this IDictionary<TK, TV> dictionary, TK key, TV defaultValue)
    {
        return dictionary.TryGetValue(key, out var value) ? value : defaultValue;
    }


    /// <summary>
    ///     从前向后查找链表中的数据，并返回第一个符合断言函数的节点。
    /// </summary>
    public static LinkedListNode<T>? FindFirst<T>(this LinkedList<T> linkedList, Predicate<T> predicate)
    {
        LinkedListNode<T>? node = linkedList.First;

        while (node != null)
        {
            if (predicate(node.Value))
            {
                return node;
            }

            node = node.Next;
        }

        return null;
    }


    /// <summary>
    ///     从后向前查找链表中的数据，并返回第一个符合断言函数的节点。
    /// </summary>
    public static LinkedListNode<T>? FindLast<T>(this LinkedList<T> linkedList, Predicate<T> predicate)
    {
        LinkedListNode<T>? node = linkedList.Last;

        while (node != null)
        {
            if (predicate(node.Value))
            {
                return node;
            }

            node = node.Previous;
        }

        return null;
    }


    public static void ForEach<T>(this IEnumerable<T> list, Action<T> callback)
    {
        foreach (var item in list)
        {
            callback(item);
        }
    }


    public static void ForEach<T>(this IEnumerable<T> list, Action<T, int> callback)
    {
        int i = 0;
        foreach (var item in list)
        {
            callback(item, i++);
        }
    }


    public static StringBuilder AppendJoin<T>(this StringBuilder builder, string separator, IEnumerable<T> values)
    {
        ArgumentNullException.ThrowIfNull(values);

        using IEnumerator<T> enumerator = values.GetEnumerator();
        if (!enumerator.MoveNext())
        {
            return builder;
        }

        T current = enumerator.Current;
        if (current != null)
        {
            builder.Append(current);
        }

        while (enumerator.MoveNext())
        {
            builder.Append(separator);
            current = enumerator.Current;
            if (current != null)
            {
                builder.Append(current);
            }
        }

        return builder;
    }

    public static bool IsAssignableTo(this Type type, Type? targetType)
    {
        return targetType != null && type.IsAssignableFrom(targetType);
    }

    // public static HashSet<T> ToHashSet<T>(this IEnumerable<T> collection)
    // {
    //     return [..collection];
    // }

    public static T ParseEnum<T>(this string value, bool ignoreCase) where T : struct
    {
        return Enum.Parse<T>(value, ignoreCase);
    }

    public static T ParseEnum<T>(this string value) where T : struct
    {
        return Enum.Parse<T>(value, false);
    }
}